package org.elanfox.intellicommunity.biz.service.core.resident.impl;

import org.elanfox.intellicommunity.biz.dto.NodeDto;
import org.elanfox.intellicommunity.biz.dto.msg.LocationMsgDTO;
import org.elanfox.intellicommunity.biz.dto.resident.StructureSaveDTO;
import org.elanfox.intellicommunity.biz.entity.equipment.CardPO;
import org.elanfox.intellicommunity.biz.entity.equipment.LocatorPO;
import org.elanfox.intellicommunity.biz.entity.resident.StructurePO;
import org.elanfox.intellicommunity.biz.entity.resident.UserPO;
import org.elanfox.intellicommunity.biz.repository.resident.StructureRepository;
import org.elanfox.intellicommunity.biz.service.core.equipment.CardService;
import org.elanfox.intellicommunity.biz.service.core.equipment.LocatorService;
import org.elanfox.intellicommunity.biz.service.core.msg.LocationMsgService;
import org.elanfox.intellicommunity.biz.service.core.resident.StructureService;
import org.elanfox.intellicommunity.biz.service.core.resident.UserService;
import org.elanfox.intellicommunity.biz.vo.UserCountVo;
import org.elanfox.intellicommunity.common.constant.DataConstant;
import org.elanfox.intellicommunity.common.resource.StaticResourceService;
import org.elanfox.intellicommunity.common.utils.StringUtilsExt;
import org.elanfox.intellicommunity.data.base.base.AbstractSearchableCrudService;
import org.elanfox.intellicommunity.data.base.base.SpecificationAndSort;
import org.elanfox.intellicommunity.data.base.dto.BaseSaveDTO;
import org.elanfox.intellicommunity.data.base.dto.BaseSearchDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;

/**
 * 社区serviceImpl
 *
 * @author loutianxi
 * @date 2019-12-06
 */
@Service
public class StructureServiceImpl extends AbstractSearchableCrudService<StructurePO, Integer> implements StructureService {

    @Autowired
    private StructureRepository structureRepository;
    @Autowired
    private LocatorService locatorService;
    @Autowired
    private StaticResourceService resourceService;
    @Autowired
    private LocationMsgService locationMsgService;
    @Autowired
    private UserService userService;
    @Autowired
    private CardService cardService;

    protected StructureServiceImpl(StructureRepository repository) {
        super(repository);
    }

    @Override
    public List<NodeDto> findTree() {
        List<NodeDto> tree = new ArrayList<>();
        List<StructurePO> allList = structureRepository.findByEnableIsTrueOrderByItemSort();
        Iterator<StructurePO> it = allList.iterator();
        //获取第一层社区结构
        while (it.hasNext()) {
            StructurePO structurePO = it.next();
            if (structurePO.getPStructureId() == DataConstant.FIRST_STRUCTURE_PARENT_ID) {
                tree.add(createNode(structurePO));
                it.remove();
            }
        }
        //递归构建社区树
        buildTree(tree, allList);
        return tree;
    }

    @Override
    public boolean deleteStr(Integer id) {
        //判断是否存在定位器
        List<LocatorPO> locatorPOS = locatorService.findByStructureId(id);
        if (!CollectionUtils.isEmpty(locatorPOS)) {
            throw new IllegalStateException("该楼层存在设备，请先移除设备");
        }
        //判断是否有子节点
        List<StructurePO> list = structureRepository.findByPStructureIdAndEnableIsTrue(id);
        if (!CollectionUtils.isEmpty(list)) {
            throw new IllegalStateException("该楼层存在子楼层，请先删除子楼层");
        }
        //删除
        structureRepository.updateEnableById(id, false);
        return true;
    }

    @Override
    public NodeDto findNode(Integer id) {
        StructurePO structurePO = findById(id);
        return createNode(structurePO);
    }

    @Override
    public List<UserCountVo> userCount(Integer structureId) {
        List<UserCountVo> list = new ArrayList<>();
        Map<Integer, Integer> countMap = countUser();
        //获取当前地图的用户数量
        StructurePO structurePO = findById(structureId);
        UserCountVo userCountVo = new UserCountVo(structurePO);
        Integer count = countMap.get(structureId);
        userCountVo.setCount(count == null ? 0 : count);
        list.add(userCountVo);
        //获取子节点
        List<StructurePO> children = findChildren(structureId);
        if (CollectionUtils.isEmpty(children)) {
            return list;
        }
        //计算子节点的人数
        for (StructurePO child : children) {
            Integer childCount = countMap.get(child.getStructureId()) == null ? 0 : countMap.get(child.getStructureId());
            UserCountVo childVo = new UserCountVo(child);
            childVo.setCount(childCount + countChildrenUser(child.getStructureId(), countMap));
            userCountVo.setCount(userCountVo.getCount() + childVo.getCount());
            list.add(childVo);
        }

        return list;
    }

    /**
     * 计算每幢楼的当前人数
     *
     * @param structureId
     * @param countMap
     * @return
     */
    private Integer countChildrenUser(Integer structureId, Map<Integer, Integer> countMap) {
        Integer count = 0;
        List<StructurePO> children = findChildren(structureId);
        if (CollectionUtils.isEmpty(children)) {
            return count;
        }
        for (StructurePO child : children) {
            Integer childCount = countMap.get(child.getStructureId());
            childCount = childCount == null ? 0 : childCount;
            count = count + childCount;
        }
        return count;
    }

    @Override
    public List<StructurePO> findChildren(Integer structureId) {
        return structureRepository.findByEnableIsTrueAndPStructureIdOrderByItemSort(structureId);
    }


    /**
     * 统计最新的定位信息，根据所在楼层计算人数
     *
     * @return
     */
    private Map<Integer, Integer> countUser() {
        List<Object> list = locationMsgService.findLastAll();
        Map<Integer, Integer> map = new HashMap<>();
        for (Object obj : list) {
            LocationMsgDTO dto = (LocationMsgDTO) obj;
            //过滤无效用户
            UserPO userPO = userService.findById(dto.getUserId());
            if (userPO == null || !userPO.isDelFlag()) {
                continue;
            }
            CardPO cardPO = cardService.find(dto.getCardId());
            if (cardPO == null || cardPO.isDeleteStatus() || !cardPO.isEnable()) {
                continue;
            }
            Integer count = map.get(dto.getStructureId());
            count = count == null ? 1 : count + 1;
            map.put(dto.getStructureId(), count);
        }
        return map;
    }

    /**
     * 构建树结构
     *
     * @param tree
     * @param list
     */
    private void buildTree(List<NodeDto> tree, List<StructurePO> list) {
        for (NodeDto parent : tree) {
            Iterator<StructurePO> it = list.iterator();
            while (it.hasNext()) {
                StructurePO child = it.next();
                if (parent.getStrId() == child.getPStructureId().intValue()) {
                    parent.getNodes().add(createNode(child));
                    it.remove();
                }
            }
            if (parent.getNodes().isEmpty()) {
                parent.setNodes(null);
            } else {
                buildTree(parent.getNodes(), list);
            }
        }
    }

    /**
     * 将社区对象转换成节点
     *
     * @return
     */
    private NodeDto createNode(StructurePO str) {
        NodeDto node = new NodeDto();
        node.setStrId(str.getStructureId());
        node.setText(str.getName());
        node.setUrl(str.getMapUrl());
        node.setPStrId(str.getPStructureId());
        node.setSort(str.getItemSort());
        node.setDesc(str.getDescription());
        node.setType(str.getType());
        if (StringUtilsExt.isNotEmpty(str.getMapUrl())) {
            try {
                node.setAllUrl(resourceService.get(str.getMapUrl()).getURI().toString());
            } catch (IOException e) {
                e.printStackTrace();
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
        }
        return node;
    }


    @Override
    public StructurePO save(BaseSaveDTO saveDTO) {
        StructureSaveDTO structureSaveDTO = (StructureSaveDTO) saveDTO;
        StructurePO structurePO = findById(structureSaveDTO.getStructureId());
        if (structurePO == null) {
            structurePO = new StructurePO();
        }
        structurePO.setMapUrl(structureSaveDTO.getMapUrl());
        structurePO.setDescription(structureSaveDTO.getDescription());
        structurePO.setEnable(true);
        structurePO.setName(structureSaveDTO.getName());
        structurePO.setItemSort(structureSaveDTO.getItemSort());
        structurePO.setType(structureSaveDTO.getType());
        //如果没有父节点，将父节点id设置成0
        structurePO.setPStructureId(structureSaveDTO.getPStructureId() == null ? DataConstant.FIRST_STRUCTURE_PARENT_ID : structureSaveDTO.getPStructureId());
        return structureRepository.save(structurePO);
    }

    @Override
    protected SpecificationAndSort<StructurePO> specificationAndSort(BaseSearchDTO searchDTO) {
        return null;
    }
}
